(* quickcheck_lib.mli *)

open Core_kernel
open Quickcheck

(** [of_array array] selects a random element from [array] to select an element *)
val of_array : 'a array -> 'a Generator.t

(** [map_gens ls ~f] maps over [ls], building one list generator using each generator
 *  returned from successive applications of [f] over elements of [ls]. *)
val map_gens : 'a list -> f:('a -> 'b Generator.t) -> 'b list Generator.t

(** [replicate_gen g n] runs [g] [n] times and returns a list of the generated
    values.
*)
val replicate_gen : 'a Generator.t -> int -> 'a list Generator.t

(** [init_gen g n] generates a list of [n] elements by calling [g] [n] times and
    passing the index into the list as a parameter.
*)
val init_gen : f:(int -> 'a Generator.t) -> int -> 'a list Generator.t

(** Like [init_gen], but returns an array. *)
val init_gen_array : f:(int -> 'a Generator.t) -> int -> 'a array Generator.t

(** [imperative_fixed_point root ~f] creates a fixed point generator which enables imperative
 *  logic (where previously generated values effect future generated values) by generating and
 *  applying a series of nested closures. *)
val imperative_fixed_point :
  'a -> f:(('a -> 'b) Generator.t -> ('a -> 'b) Generator.t) -> 'b Generator.t

val gen_pair : 'a Generator.t -> ('a * 'a) Generator.t

(** Generate a shuffle of an array, uniform distribution. Non-side-effecting. *)
val shuffle_arr : 'a array -> 'a array Generator.t

(** Like [shuffle_arr] but for a list. *)
val shuffle : 'a list -> 'a list Generator.t

(** [gen_division n k] generates a list of [k] integers which sum to [n] *)
val gen_division : int -> int -> int list Generator.t

(** Like [gen_division], but generates a list of currency amounts. [n] must be
    <= Int.max_value or an exception will be thrown. *)
val gen_division_currency :
  Currency.Amount.t -> int -> Currency.Amount.t list Generator.t

(** [gen_imperative_list ~p head_gen elem_gen] generates an imperative list
 *  structure generated by [elem_gen], starting from an initial element
 *  generated by [head_gen]. [head_gen] generates a function that will be called
 *  with a pervious node in order to build the list *)
val gen_imperative_list :
  'a Generator.t -> ('a -> 'a) Generator.t -> 'a list Generator.t

(** [gen_imperative_ktree ~p root_gen node_gen] generates an imperative ktree structure
 *  as a flat list of nodes, generated by [node_gen], starting from a root generated by [root_gen].
 *  [node_gen] generates a function that will be called with the parent node in order to build
 *  the tree. The value [p] is the geometric distribution (or "radioactive decay") probability
 *  that is determines the number of forks at each node. Sizes of forks in the tree are
 *  distributed uniformly. *)
val gen_imperative_ktree :
  ?p:float -> 'a Generator.t -> ('a -> 'a) Generator.t -> 'a list Generator.t

val gen_imperative_rose_tree :
     ?p:float
  -> 'a Generator.t
  -> ('a -> 'a) Generator.t
  -> 'a Mina_stdlib.Rose_tree.t Generator.t
